﻿using System;
using System.Windows;
using Columbus.Controls;

namespace Columbus.ActionResults
{
    /// <summary>
    /// View Result is base class for action results displaying views
    /// </summary>
    public abstract class ViewResult : ActionResult
    {
        private readonly string viewName;
        private readonly object model;
        private readonly Frame navigationFrame;
        private readonly Func<string, FrameworkElement> viewLocator;
        private readonly INavigator navigator;
        private readonly IApplicationSettings applicationSettings;

        /// <summary>
        /// Initializes a new instance of the <see cref="ViewResult"/> class.
        /// </summary>
        /// <param name="viewName">Name of displayed view.</param>
        /// <param name="model">(View) model.</param>
        /// <param name="context">Navigation ontext.</param>
        protected ViewResult(string viewName, object model, NavigationContext context)
            : base(context)
        {
            this.viewName = viewName;
            this.model = model;
            navigationFrame = context.Navigator.NavigationFrame;
            viewLocator = context.ViewLocator;
            navigator = context.Navigator;
            applicationSettings = context.ApplicationSettings;
        }

        /// <summary>
        /// Gets name of the view.
        /// </summary>
        /// <value>The of the view.</value>
        public string ViewName
        {
            get { return viewName; }
        }

        /// <summary>
        /// Gets (view)model.
        /// </summary>
        /// <value>The (view)model.</value>
        public object Model
        {
            get { return model; }
        }

        /// <summary>
        /// Executes result.
        /// </summary>
        protected override void ExecuteInternal()
        {
            Dispatcher.Dispatch(() =>
            {
                var view = viewLocator(viewName);
                view.Name = viewName;
                
                var viewModel = model as ViewModel;
                if (viewModel != null)
                {
                    viewModel.Navigator = navigator;
                    viewModel.ApplicationSettings = applicationSettings;
                }

                view.DataContext = model;
                RenderView(navigationFrame, view);
            });
        }

        /// <summary>
        /// Renders view.
        /// </summary>
        /// <param name="navigationFrame">Navigation frame.</param>
        /// <param name="view">View.</param>
        protected abstract void RenderView(Frame navigationFrame, FrameworkElement view);
    }
}